package com.oig.sys.security.support;


import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;


/**
 * 原来 spring-cloud-starter-oauth2项目已停止
 *
 * token校验都是需要访问一次认证中心，每一次请求resource服务，都会由过滤器去执行远程访问。
 * opaque token  请求认证中心/oauth2/introspect端点 认证中心判断 client下 有没有这个token，token是否生效
 * jwt token做法让前端去存用户数据，authentication-server颁发jwt token时加签名， 资源服务一样需要去认证中心拿公钥验证签名
 *
 *  权限校验不用请求认证中心
 *  opaque token,
 *    1、修改认证中心 /oauth2/introspect端点返回的数据 返回完整含了权限的securityUser对象信息，并修改OpaqueTokenIntrospector
 *    2、authorization-server把token内容存储到数据库（redis/mysql等），OpaqueTokenIntrospector去存储服务器查到 securityUser对象，还不如直接用sa-token？
 *    这样 hasPermission取权限标识符来比对，authorities中没有匹配的权限直接抛 AccessDeniedException异常了
 *    需求鉴权每次都需要去认证中心，拿securityUser,解析判断权限，消耗内网流量
 *
 *  jwt可以扩展直接把需要的内容，放到jwt。 jwt做法坏处是，jwt一旦签发就有效，只到过期，服务端无法主动让jwt失效。
 *    每次请求，前端传过来扩展的jwt，需要鉴权，就需要每次解析拿到，SecurityUser对象信息，消耗外网流量
 *
 *  另外怎么用好 scopes？
 */
@Slf4j
public class PermissionVerifyService {

    /**
     * 判断接口是否有xxx:xxx权限
     * @param permission 权限
     * @return {boolean}
     */
    public boolean hasPermission(String permission) {
        if (StrUtil.isBlank(permission)) {
            return false;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        log.debug("authentication:{}", authentication);
        if (authentication == null) {
            return false;
        }
        if (authentication.getPrincipal() instanceof SecurityUser){
            SecurityUser principal = (SecurityUser) authentication.getPrincipal();
            Collection<? extends GrantedAuthority> authorities = principal.getAuthorities();
            return this.checkRole(permission, authorities);
        }
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();   //security框架本身返回的 scope的内容
        return this.checkRole(permission, authorities);
    }


    private boolean checkRole(String permission, Collection<? extends GrantedAuthority> authorities){
        return authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText)
                .anyMatch(x -> {
                    log.debug("default -->x:{},permission={} --{}",x, permission, PatternMatchUtils.simpleMatch(permission, x));
                    return PatternMatchUtils.simpleMatch(permission, x) ;
                });
    }

}
